Support sealed (exhaustive) whens
一言で表すと
sealed classに対してwhenするときに網羅的にする必要がある
概要
課題と提案
以下は現時点でエラーにならない
code:kotlin
sealed class Mode {
object ON : Mode()
object OFF : Mode()
}
val x: Mode = Mode.ON
when(x) {
Mode.ON -> println("ON")
}
これは網羅的でないことがわかりにくいし、追加したときにもコンパイルが通ってしまう
また、enum, selaed class / interface, booleanで結果が異なる
code:kotlin
// enum: 警告が表示される
// WARNING: NON_EXHAUSTIVE_WHEN 'when' expression on enum is recommended to be exhaustive, add 'OFF' branch or 'else' branch instead enum class Mode { ON, OFF }
val x: Mode = Mode.ON
when(x) {
Mode.ON -> println("ON")
}
// sealed class / interface: コンパイル中は表示されず、IDEでのみ情報が表示される
sealed class Mode {
object ON : Mode()
object OFF : Mode()
}
val x: Mode = Mode.ON
when(x) {
Mode.ON -> println("ON")
}
// boolean: なにもない
val x: Boolean = true
when(x) {
true -> println("true")
}
これらを全てエラーにする
回避策
現在の挙動を変えたくない場合はelse句を追加する
code:kotlin
enum class Mode { ON, OFF }
val x: Mode = Mode.ON
when(x) {
Mode.ON -> println("ON")
else -> {}
}
網羅的でないことが明確になる
移行計画
問題のあるコードが警告で表示される
code:kotlin
kotlin {
sourceSets.all {
languageSettings.apply {
languageVersion = "1.6"
//progressiveMode = true // 警告ではなくエラーにする
}
}
}
kotlin 1.6で警告にする
kotlin 1.7でエラーにする
デザインノートと根拠的理由
whenが式の場合、以前から網羅的でなければコンパイルエラーになっていた
検討された代替案
exhaustive when(x) { ... } のようなオプトイン方式の代替案も考えられた
when式とwhen文をリファクタする際に妨げとなる
通常の場合、開発者はwhenを網羅的に使っているし、使いたがっている。Kotlin言語の主要な設計原則であるコードを書くための最も一般的で最も正しい方法はデフォルトのより短い構文を持つべきであるという法則に反する
コメントからピックアップ
else -> {} という記法が気にならなければ else -> Unit が使える
code:kotlin
enum class Mode { ON, OFF }
val x: Mode = Mode.ON
when(x) {
Mode.ON -> println("ON")
else -> Unit
}
horis.icon tashikani
code:kotlin
fun Any.exhaustive() = Unit
をwhenにAWAではつけてました
気になるポイント
コメント
Jakeのライブラリ